#pragma once
#include <iostream>
#include <string>
#include <ctime>
#include <cstdarg>
#include <pthread.h>
#include <fstream>
using namespace std;

//##__VA_ARGS__ 中的 ## 操作符。当 __VA_ARGS__ 为空时（即没有额外的参数），## 操作符会将其前面的逗号去掉，以防止在编译时产生语法错误。
#define Log(level, format, ...) do{LogMessage(__FILE__, __LINE__, level, format, ##__VA_ARGS__);}while(0)
#define YSave do{IsSave = true;}while(0)
#define NSave do{IsSave = false;}while(0)

pthread_mutex_t log_mutex = PTHREAD_MUTEX_INITIALIZER;
string file_name_path = "log.txt";
bool IsSave = false; 

enum Level
{
    Debug = 0,
    Info,
    Warning,
    Error,
    Fatal
};

string LevelToString(int level)
{
    string name;
    switch (level)
    {
    case Debug   : return "Debug";
    case Info    : return "Info";
    case Warning : return "Warning";
    case Error   : return "Error";
    case Fatal   : return "Fatal";
    default: return "阿西吧";
    }
}

string TimeToString()
{
    time_t Time; time(&Time);
    struct tm* attr = localtime(&Time);

    char buffer[1024];
    sprintf(buffer,"%4d-%2d-%2d %2d:%2d:%2d",
                    attr->tm_year+1900,
                    attr->tm_mon+1,
                    attr->tm_mday,
                    attr->tm_hour,
                    attr->tm_min,
                    attr->tm_sec);
    
    return buffer;
}

void Save(string ret)
{
    fstream out(file_name_path.c_str(), ios::app); 
    if(out.is_open())
    {
        out << ret;
    }
    else
    {
        std::cerr << "无法打开文件: " << file_name_path << std::endl;
    }
    out.close();
}

// 2. 日志是有格式的
// 日志等级 时间 代码所在的文件名/行数 日志的内容
void LogMessage(string filename, int line, int level, const char* format, ...)
{
    string levelname = LevelToString(level);
    string timename = TimeToString();

    va_list args;           //一个void*指针
    va_start(args, format); //将args初始化，指向可变参数列表
    char buffer[1024]; vsprintf(buffer, format, args);
    va_end(args);

    string ret = "[" + filename + "]" + "[" + "line: " + to_string(line) + "]" + "[" + levelname + "]" + "[" + timename + "]" + "[" + buffer + "]" + "\n";
    
    pthread_mutex_lock(&log_mutex);
    if(IsSave)
    {
        Save(ret);
    }
    else
    {
        cout << ret;
    }
    pthread_mutex_unlock(&log_mutex);
}




